package com.gzhryc.common.event;

import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

import com.gzhryc.common.logging.Logger;

/**
 * 超时移除的HashMap对象
 * 
 * @author apple
 * 
 * @param <K>
 * @param <V>
 */
public class TimingHashMap<K, V> extends ConcurrentHashMap<K, V> {

	static Logger log = Logger.getLogger(TimingHashMap.class);

	private static final long serialVersionUID = 1L;

	private ConcurrentHashMap<K, ExpireCheckTask> tasks;

	private Long timeout;
	private Timer timer;
	private Callback<K,V> callback;

	/**
	 * 构建方法
	 * 
	 * @param timeout 超时移除时间（秒）
	 */
	public TimingHashMap(Long timeout) {
		super();
		this.timeout = timeout * 1000;	//秒转化成毫秒
		this.timer = new Timer();
		this.tasks = new ConcurrentHashMap<K, ExpireCheckTask>();
	}

	public TimingHashMap(Long timeout, Callback<K,V> callback) {
		super();
		this.timeout = timeout * 1000;	//秒转化成毫秒
		this.timer = new Timer();
		this.tasks = new ConcurrentHashMap<K, ExpireCheckTask>();
		this.callback = callback;
	}

	@Override
	public V put(K key, V value) {
		if (this.containsKey(key)) {
			this.tasks.get(key).cancel();
		}
		V v = super.put(key, value);
		ExpireCheckTask task = new ExpireCheckTask(this, tasks, key, timeout, callback);
		this.tasks.put(key, task);
		try {
			this.timer.schedule(task, timeout);
		} catch (IllegalStateException e) {
			// 如果定时器错误就重新
			this.timer = new Timer();
			for (ExpireCheckTask item : tasks.values()) {
				this.timer.schedule(item, timeout);
			}
		}
		return v;
	}

	@Override
	public V remove(Object key) {
		V v = super.remove(key);
		ExpireCheckTask task = this.tasks.remove(key);
		if (task != null) {
			task.cancel();
		}
		return v;
	}

	public V get(Object key, boolean refresh) {
		V v = super.get(key);
		if (refresh) {
			ExpireCheckTask task = this.tasks.get(key);
			if (task != null) {
				task.setDatetime(System.currentTimeMillis());
			}
		}
		return v;
	}

	@Override
	public V get(Object key) {
		return get(key, false);
	}

	/**
	 * 取出值并删除
	 * 
	 * @param key
	 * @return
	 */
	public V pop(Object key) {
		V v = super.get(key);
		this.remove(key);
		return v;
	}

	@Override
	public void clear() {
		super.clear();
		for (ExpireCheckTask task : tasks.values()) {
			task.cancel();
		}
		tasks.clear();
	}

	public static class ExpireCheckTask extends TimerTask {

		private AtomicBoolean isCancel = new AtomicBoolean(false);
		private final Map<?, ExpireCheckTask> tasks;
		private final Map<?, ?> map;
		private Object key;
		private Long datetime;
		private Long timeout;
		private Callback callback;

		public ExpireCheckTask(Map<?, ?> map, Map<?, ExpireCheckTask> tasks, Object key, Long timeout,Callback callback) {
			this.map = map;
			this.key = key;
			this.timeout = timeout;
			this.isCancel = new AtomicBoolean(false);
			this.tasks = tasks;
			this.datetime = System.currentTimeMillis();
			this.callback = callback;
		}

		public void run() {
			if (!isCancel.get() && System.currentTimeMillis() - datetime >= timeout) {
				Object value = this.map.remove(key);
				this.tasks.remove(key);
				this.cancel();

				if(callback != null){
					callback.remove(key,value);
				}

				log.debug("移除Key=" + key + "的对象，当前缓存数：" + this.map.size() + "，当前任务数：" + this.tasks.size());
			}
		}

		public boolean cancel() {
			isCancel.set(true);
			return super.cancel();
		}

		public void setDatetime(Long datetime) {
			this.datetime = datetime;
		}
	}

	public static interface Callback<K,V> {

		public void remove(K key,V value);
	}
}
